- Friday, September 27, 2024
In the realm of React development, achieving better component decoupling is essential for creating maintainable and reusable code. A common scenario involves an onboarding component that transitions through various steps, such as WelcomeStep, TermsOfServiceStep, and CompleteStep. A typical implementation might involve a state variable to track the current step and pass a state setter function down to child components. While this approach works, it introduces tight coupling between the parent and child components, which can lead to several issues. The tight coupling arises because the child components gain direct access to the parent's internal state management. This can break encapsulation, making it difficult to troubleshoot issues since the parent loses control over how its state is modified. If a child component can change the parent's state in unexpected ways, it complicates debugging and can lead to unintended side effects. Additionally, this setup can result in unnecessary re-renders, as the child components dictate when the parent should update its state, rather than the parent controlling its own updates. To address these concerns, a more effective solution is to have the child components provide callback functions to the parent. This approach allows the parent to maintain control over its state while still enabling the child components to signal when an action should occur. For instance, instead of passing a setter function directly, the parent can pass a callback like `onClickNext`, which the child can invoke when it needs to trigger a state change. This method not only reduces coupling but also enhances the reusability and testability of the child components. A practical example of this revised approach can be seen in the updated implementation of the onboarding component. The parent component retains the state management but now calls the setter function within its own context, using the callback provided by the child. This design allows for more complex logic to be incorporated into the callback if needed, while also simplifying the interface of the child components. When designing components, it is crucial to consider their interfaces carefully. By thinking of components in isolation, developers can create simpler, more intuitive, and reusable components that are easier to test. This focus on decoupling and interface design ultimately leads to a more robust and maintainable codebase, enhancing the overall development experience in React.
- Friday, September 13, 2024
React 19 introduces major updates like Server Components, improving performance by rendering on the server and reducing client-side JavaScript. New features include Actions for handling events and enhanced hooks like useActionState for managing form states, streamlining both server and client workflows.
- Friday, September 6, 2024
React 19 beta introduces new hooks like useTransition and useActionState to streamline async handling, improve form management, and enable optimistic updates for smoother user experiences. These features reduce unnecessary re-renders, automate state management, and improve UI responsiveness during async operations.
- Thursday, May 23, 2024
React 19 has features like Server Components and Server Actions, which optimize performance and simplify data handling by shifting more logic to the server. Server Actions make API endpoint creation and form handling easier by automatically managing pending UI states, error handling, and optimistic UI updates.
- Thursday, September 26, 2024
The blog post discusses the concept of component composition in React, emphasizing its significance as a core advantage of the framework. Initially, the author reflects on their early experiences with React, highlighting features like the Virtual DOM, one-way data flow, and JSX. However, they argue that the true strength of React lies in its ability to compose components into more complex structures, a practice that was not widely accepted in software development a decade ago. The author addresses the traditional notion of separation of concerns, suggesting that while it still exists, it has evolved. Instead of separating styles, logic, and markup into distinct layers, React encourages grouping them together within components, leading to better code cohesion. This shift allows developers to think in terms of components, which can enhance the organization and maintainability of code. The discussion then shifts to conditional rendering, a common practice in React where components are rendered based on certain conditions. The author presents an example of a `ShoppingList` component that conditionally renders user information and items based on the presence of data. While this approach is acceptable for simple cases, the author warns that it can become problematic when managing multiple states within a single component. As the complexity of the component increases, the author illustrates how conditional rendering can lead to a convoluted structure that is difficult to read and maintain. They propose breaking down the component into smaller, more manageable pieces, suggesting the use of a layout component to encapsulate shared elements while allowing for dynamic content based on the component's state. The author advocates for using early returns to handle different states of a component more clearly. By returning early for each state (e.g., loading, no data, or displaying data), the code becomes easier to follow and reduces cognitive load. This method also facilitates the addition of new conditions, such as error handling, without complicating the existing logic. The post concludes by emphasizing the importance of component composition and the need to avoid excessive conditional rendering. The author encourages developers to embrace early returns and to continually reassess their component structures to ensure clarity and maintainability. They invite readers to engage with them for further discussion or questions, reinforcing the community aspect of learning and sharing knowledge in the React ecosystem.
- Wednesday, May 8, 2024
React Query and React Context can be used together to manage data dependencies and make component logic simpler. Combining both makes implicit dependencies (like knowing a query has been executed elsewhere) clear and visible in your code.
- Wednesday, March 6, 2024
React 19 introduces several significant improvements designed to streamline development and boost application performance. Key features include a performance-enhancing compiler, simplified form handling with Actions, server-side rendering optimizations with Server Components, and better integration with Web Components. The update promises faster rendering, smoother user experiences, and easier development workflows.
- Wednesday, July 3, 2024
React Server Components (RSC) are primarily server-side components that optimize performance by fetching data and rendering on the server, while Client Components handle interactivity and state management on the client side. In the RSC paradigm, Server Components are the default, and Client Components are explicitly marked using 'use client'. While Server Components cannot be directly nested within Client Components, they can be passed as props to Client Components.
- Tuesday, June 25, 2024
MobX, a React state management library, automatically tracks dependencies and memoizes components. The upcoming React Compiler is meant to auto-memoize components, but MobX already does this more efficiently with less memory.
- Friday, August 9, 2024
This is a practical guide to refactoring a messy React component through gradual improvements. First, one should make sure that tests are written so that no functional changes occur during refactoring. Then, linting rules should be used to prevent future code duplication and dead code. The guide highlights several key areas for refactoring, including splitting components based on responsibilities and extracting utility functions to improve code organization and maintainability.
- Friday, May 24, 2024
In React, closures combined with the useCallback hook can cause hidden memory leaks by holding onto large objects in the component's context, preventing garbage collection. Memoized functions may inadvertently reference each other and shared data, creating an endless chain of closures. To avoid such issues, keep closure scopes small, avoid unnecessary memoization, and consider using useRef for large objects.
- Building a React-like library from scratch to understand its internal workings and design decisions.Monday, September 2, 2024
This article details the process of building a React-like library from scratch, providing insights into its internal workings and design decisions. It starts by implementing a core rendering model, including components, virtual DOM, and reconciliation, showing how React constructs and updates the UI. It then goes into the implementation of essential hooks like `useState`, `useRef`, `useEffect`, and `useMemo`. Finally, the article discusses the implementation of `useCallback` and `useContext`, showing off the challenges and solutions involved in managing state and context sharing within a component tree.
- Tuesday, April 16, 2024
React Server Components (RSCs) allow server-exclusive code, which can lead to better performance. However, this means that popular styling options, like CSS-in-JS libraries which rely on React's lifecycle, can conflict with RSCs. RSC's server-side focus clashes with the browser-centric nature of traditional CSS-in-JS libraries, but there are “zero-runtime” CSS-in-JS libraries that are fully compatible with RSCs today. If your application doesn't use these and already has a good “time-to-interactive” time, then migrating to these libraries is not worth it.
- Friday, August 2, 2024
React introduced the concept of a "virtual DOM" to optimize web app rendering. Its popularity led to widespread adoption, but also to criticisms regarding its learning curve, state management, and performance. While React's defenders highlight its improvements in recent versions, alternative frameworks like Svelte and Astro offer simpler approaches without relying on the virtual DOM.
- Thursday, August 15, 2024
This article introduces three key rules to manage React side effects properly: keep side effects out of the render process, place side effects triggered by events in event handlers, and use useEffect to handle side effects that synchronize with external systems.
- Thursday, May 16, 2024
This article explains how to build a simplified version of React with 400 lines of code. The simplified React utilizes Fiber architecture and concurrency mode to avoid blocking the main thread during rendering. It is able to execute tasks during browser idle time. It uses a linked list structure to connect work units and triggers updates through a custom useState implementation.
- Friday, October 4, 2024
React hooks have become an integral part of modern React development, yet there are nuances and unspoken rules that can complicate their use. Tom MacWright shares his insights on these complexities, particularly focusing on the useEffect hook and its dependency management. One of the primary rules regarding useEffect is that the dependency array should include all variables referenced within the callback function. For instance, if a developer uses a state variable like `x` in a useEffect without including it in the dependency array, it can lead to unexpected behavior. The correct implementation would ensure that `x` is included in the dependencies, thus allowing React to track changes to that variable effectively. However, not all values need to be included in the dependency array. Some values are considered "known to be stable," meaning they do not change between renders. Examples of these stable values include state setters from useState, dispatchers from useReducer, refs from useRef, and certain return values from hooks like useEffectEvent. These stable references do not need to be added to the dependencies array, which can simplify the management of effects. MacWright expresses frustration with the lack of clarity in React's documentation regarding the stability of these values. The reliance on object identity and stability can lead to confusion, especially for developers who may not be aware of the implications of including unstable references in the dependency array. This can result in effects running more frequently than intended, which can degrade performance and lead to bugs. The documentation does touch on some aspects of stability, but it is often scattered across different sections rather than being consolidated in the API documentation for each hook. This can make it challenging for developers to ascertain whether the return values from third-party hooks, such as those from libraries like Jotai or tanstack-query, are stable. The uncertainty surrounding these third-party hooks adds another layer of complexity to dependency management in React. Despite these challenges, MacWright notes that including stable values in the dependency array is not detrimental; it simply means that the effect will not trigger unnecessarily. However, he advocates for clearer documentation and better tools to help developers understand which values are stable and which are not. This would enhance the overall experience of working with React hooks and improve the reliability of applications built with them.
- Friday, May 10, 2024
Many developers work professionally with React for years without understanding how its re-rendering process works. This tutorial helps readers build a mental model for when and why React re-renders and how to tell why a specific component re-rendered. Knowing how React's render cycle works can help developers understand when to use React.memo and when to wrap functions in useCallback.
- Tuesday, May 28, 2024
This article presents a way to implement React-like component-based frontend development in Go using the standard library. Its approach defines components using the define function, composes them using templates, and manages state using URL query parameters.
- Friday, October 4, 2024
Since its introduction in 2013, React has evolved significantly, leading to the emergence of various component types. This evolution has resulted in some components becoming essential for modern applications, while others have fallen out of favor or been deprecated. This guide aims to provide beginners with a comprehensive understanding of the different types of React components, highlighting both legacy and modern patterns. Initially, React relied on the `createClass` method for defining components, which allowed developers to create class components without using JavaScript classes. This method was prevalent before the introduction of ES6 in 2015, which brought native class syntax to JavaScript. The `createClass` method enabled developers to define component state and lifecycle methods, although it has since been deprecated and is no longer part of the React core package. Another early pattern was React Mixins, which allowed for the extraction of reusable logic from components. Mixins could encapsulate functionality and be included in components, but they have also been deprecated due to their drawbacks, such as potential naming conflicts and difficulties in tracking the source of methods. With the release of React 0.13, Class Components became the standard for defining components, utilizing ES6 class syntax. Class Components introduced lifecycle methods and allowed for more structured component logic. However, with the introduction of React Hooks in version 16.8, Function Components gained the ability to manage state and side effects, making them the preferred choice for modern React development. Higher-Order Components (HOCs) were another advanced pattern that allowed for the reuse of component logic by wrapping components with additional functionality. However, like Mixins and Class Components, HOCs have seen a decline in usage as developers increasingly favor Function Components with Hooks for sharing logic. Function Components, which were once limited to stateless behavior, have transformed with the introduction of Hooks. They now allow developers to manage state and side effects, making them the industry standard. Custom Hooks can also be created to encapsulate and share logic across components, providing a more modular approach compared to previous patterns. The latest addition to React is Server Components, which enable components to be executed on the server. This approach allows for the delivery of only HTML to the client, optimizing performance and enabling access to server-side resources. Server Components differ from traditional Client Components, which run in the browser and can utilize JavaScript and React Hooks. Async Components are currently supported for Server Components, allowing for asynchronous operations like data fetching before rendering. This capability is expected to extend to Client Components in the future, further enhancing the flexibility of React. Overall, this guide has explored the various types of React components, their historical context, and their relevance in modern development. Understanding these components is crucial for developers looking to build efficient and maintainable React applications.
- Tuesday, May 14, 2024
React Query is both a data fetcher and an asynchronous state manager designed for handling server state. Unlike client state (managed with useState or useReducer), server state is often asynchronous, persistent, and can be modified by multiple users. React Query abstracts common complexities like cache management, invalidation, and refetching, allowing developers to focus on building their applications without getting bogged down in the complex, nitty-gritty details of data fetching.
- Friday, August 16, 2024
Dependency Injection (DI) is a design pattern that improves flexibility, testability, and maintainability by injecting external dependencies into your code rather than hard-coding them. In React applications, DI can be implemented using createContext and useContext to manage dependencies across components without prop drilling. This approach simplifies testing, makes code less coupled, and provides better separation of concerns, though it does add some complexity.
- Monday, June 10, 2024
React Compiler is an experimental tool that aims to automate the memoization of components and dependencies Initial tests on simple examples showed promising results, with the Compiler successfully eliminating unnecessary re-renders. However, when applied to real-world applications, the Compiler struggles with complex scenarios and requires developers to have a deep understanding of memoization techniques and React's internal workings to make necessary code adjustments for optimal Compiler results.
- Thursday, May 2, 2024
Excessive null/undefined value checking in React components is difficult to deal with as a codebase grows, especially if the codebase is poorly typed.
- Friday, April 12, 2024
Flow, a type checker for JavaScript, now offers dedicated syntax for React components and hooks to improve the developer experience. It now replaces traditional React function syntax with component syntax and enforces React best practices, like making props read-only. It also supports hooks and their corresponding rules.
- Thursday, August 8, 2024
This article explains how React compiler works, specifically how it applies memoization techniques for efficiency on functions and hooks. The compilation involves traversing nodes, compiling functions, and replacing original functions with optimized versions. If memoization is applied, the compiler adds an import for `useMemoCache`. The article details the compiler's operation from entry through Babel to function transformation.
- Wednesday, August 21, 2024
With the addition of Server Components and Server Actions, React is evolving into a full-stack framework.
- Friday, October 4, 2024
In the realm of React development, a common feature request is to make application screens shareable via URLs. This request often leads to bugs, particularly when managing state within React components. A practical example of this is a searchable table that fetches data from a server. The initial implementation uses local React state to manage the search input, which works well until the page is reloaded. Upon reloading, the search text and table data are lost, highlighting the need for a solution that allows the state to persist through URL parameters. To address this, the approach involves syncing the React state with the URL. By utilizing the `useEffect` hook, developers can update the URL whenever the search input changes. In a Next.js application, this can be achieved by leveraging the `useRouter` and `usePathname` hooks to modify the URL dynamically based on the search input. However, this creates a new challenge: when the page is reloaded, the UI does not reflect the URL's state, leading to inconsistencies. To resolve this, the `useSearchParams` hook can be employed to initialize the search state from the URL parameters. This ensures that when the page is loaded or reloaded, the search input reflects the current URL state. However, this introduces a potential issue with state duplication, as both the React state and the URL can hold the search text, leading to synchronization problems when navigating with the browser's back and forward buttons. The solution lies in treating the URL as the single source of truth for the search text. By removing the local React state and deriving the search text directly from the URL parameters, developers can eliminate the risk of state duplication. This means that any changes made in the input field will directly update the URL, and vice versa, ensuring that the UI remains consistent across different interactions, including page reloads and navigation. The final implementation allows for seamless interaction: typing in the search box updates the URL, and refreshing the page or using the back and forward buttons keeps the search input and table data in sync. Additionally, if the search input is cleared, the URL is reset accordingly, maintaining a clean and functional user experience. This approach emphasizes the importance of having a single source of truth in applications, particularly when dealing with dynamic data that exists outside of React, such as URL parameters. By recognizing and eliminating duplicated state, developers can create more robust and maintainable applications. The discussion also touches on broader concepts of state management in React, suggesting that as applications evolve, state may need to be lifted to external systems, reinforcing the idea that understanding how to manage state effectively is crucial for React developers. In conclusion, the article highlights the significance of syncing React components with URL parameters to create shareable and consistent user experiences. It encourages developers to be mindful of state management practices and to consider external sources of truth when designing their applications. The author also hints at further exploration of these concepts in an upcoming course focused on advanced React patterns, promising to delve deeper into state management and other core React principles.
- Monday, August 12, 2024
This article explains how to create a simple React state management library using the `useSyncExternalStore` hook introduced in React 18. It outlines the key components of the library, including subscribing to state changes, retrieving the current state, and updating the state. The article also compares this approach to using React Context and discusses potential improvements like using reducers and immer for state management.
- Thursday, July 11, 2024
The new React compiler has some limitations in addressing memory leaks caused by closures, particularly in the context of memoization hooks. While the compiler effectively caches values that don't depend on state or props, it doesn't prevent the underlying issue of shared closure contexts that can lead to prolonged memory retention. The author demonstrates this with a code example where creating a new object dependent on state within a memoized function results in a memory leak despite the compiler's memoization.